package com.atguigu.juc.interrupt;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author yanglin
 * @create 2024-01-09 9:19 星期二
 * description:   注意：代码从下到上依次递进
 */
public class InterruptDemo {

    /**
     *  一个程序不应该由其他程序来强制中断或停止，而是应该由线程自己自行停止，
     *  所以 Thread.stop   Thread.suspend   Thread.resume 都以被废弃
     *  
     *  在Java中没有办法立刻停掉一条线程，但在某些情况下又不得不停止一个线程（例如：取消一个耗时操作），
     *  因此，Java提供了一种用于停止线程的协商机制---中断   即中断标识协商机制
     *  
     *  中断只是一种协作协商机制，Java没有给中断增加任何语法，中断的过程需要程序员自己实现
     *  若要中断一个线程，需要手动调用该线程的interrupt方法，该方法也仅仅是将线程对象的中断标识设置为true，
     *  接着，你需要通过自定义代码不断的监测当前的中断标识位是否为true，标识别的线程请求这条线程中断
     *  
     *  每个线程对象都有一个线程标识位，用于标识线程是否被中断，该标识位为true表示中断，为false表示未中断
     *  通过调用线程对象的interrupt方法将该线程的标识位设置为true，可以在别的线程中调用，也可以在自己的线程中调用
     *  
     *  中断API之三大方法：
     *      interrupt()       仅仅是设置线程的中断状态为true，发起一个协商而不会立刻停止线程
     *      interrupted()     静态方法，判断线程是否被中断，并清除当前中断状态
     *                             1、返回线程当前的中断状态，测试当前线程是否以被中断
     *                             2、将当前线程的中断状态清零并重新设置为false，清除线程的中断状态
     *      isInterrupted()   实例方法，判断当前线程是否被中断（通过监测中断标志位）
     *      
     *  如何停止中断运行中的线程？
     *      通过volatile实现线程中断，因为被volatile修饰的变量，线程之间可见
     *      通过AtomicBoolean实现线程中断
     *      
     *      总结：
     *          当一个线程调用interrupt()时，如果线程处于正常活动状态，那么将线程的中断标志位设置为true，仅此而已
     *          被设置中断标志的线程将继续正常运行，不受影响
     *          所以：interrupt()并不能真正的中断线程，需要被调用的线程配合才能完成中断
     *  
     *          如果线程处于被阻塞状态（sleep wait join）,在别的线程中调用当前线程的interrupt方法
     *          那么线程将立刻退出被阻塞状态，并抛出一个interruptException异常
     *   
     *   当前线程的中断标识为true，是不是线程立刻停止？
     *      详见方法：m4_interrupt2
     *      
     *  
     */
    
    static volatile boolean isStop = false;
    
    static AtomicBoolean atomicBoolean = new AtomicBoolean(false);

    
    public static void main(String[] args) {

    }

    /**
     * 静态方法 interrupted() 方法的测试
     */
    public static void m6_interrupted() {
        //测试当前线程是否被中断（检查中断标志），返回一个Boolean并清除中断状态
        //第二次在调用时，中断已被清除，将返回一个false
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.interrupted());   //默认 false
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.interrupted());   //false
        System.out.println("---1");
        Thread.currentThread().interrupt();   //将中断标志位设置为true
        System.out.println("---2");
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.interrupted());   //true
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.interrupted());    //false
    }

    public static void m5_interrupt() {
        Thread t1 = new Thread(() -> {
            while (true){
                if (Thread.currentThread().isInterrupted()){
                    System.out.println(Thread.currentThread().getName() + "\t 中断标志位：" + Thread.currentThread().isInterrupted() + "程序停止");
                    break;
                }

                /**
                 *  如果线程处于被阻塞状态（sleep wait join）,在别的线程中调用当前线程的interrupt方法
                 *  那么线程将立刻退出被阻塞状态，并抛出一个interruptException异常
                 *  
                 *  分析：
                 *      1、中断标志位默认是false
                 *      2、t2 对 t1 发出了中断协商 t2调用了 t1.interrupt() 中断标志位为true
                 *      3、中断标志位为true   正常情况  程序停止
                 *      4、中断标志位为true 异常情况InterruptedException   将会把中断状态清除，并且收到InterruptedException
                 *          中断标志为变为false，导致无限循环
                 *      5、在catch块中，需要再次给中断标志位设置为true，程序才能停止
                 *  
                 */
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();    //为什么要在异常处在调用一次？
                    e.printStackTrace();
                }

                System.out.println("------hello interrupt demo03");
            }
        }, "t1");
        t1.start();

        //暂停1秒
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            t1.interrupt();
        }, "t2").start();
    }


    /**
     * 当前线程的中断标识为true，是不是线程立刻停止？   //不会立刻停止
     */
    public static void m4_interrupt2() {
        //实例方法interrupt()仅仅是设置线程的中断状态为true，不会停止线程
        Thread t1 = new Thread(() -> {
            //中断标识被设置为true后，不能立刻停止线程
            for (int i = 0; i < 300; i++) {
                System.out.println(i);
            }
            System.out.println("t1线程调用interrupt()后的中断标识02：" + Thread.currentThread().isInterrupted());
        }, "t1");
        t1.start();

        System.out.println("t1线程的默认中断标志：" + t1.isInterrupted());  //false

        try {
            TimeUnit.MILLISECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        t1.interrupt(); //true

        System.out.println("t1线程调用interrupt()后的中断标识：" + t1.isInterrupted());  //true

        try {
            TimeUnit.MILLISECONDS.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //2秒后，t1线程已经停止，中断不活动的线程不会造成任何影响
        System.out.println("t1线程调用interrupt()后的中断标识03：" + t1.isInterrupted());
    }


    //通过interrupt api 实现
    public static void m3_interrupt() {
        Thread t1 = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println(Thread.currentThread().getName() + "\t isInterrupted()被修改为: " + "true" + ", 程序停止");
                    break;
                }
                System.out.println("通过 isInterrupted() 来实现中断线程");
            }
        }, "t1");
        t1.start();

        try {
            TimeUnit.MILLISECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            t1.interrupt();
        },"t2").start();
    }


    /**
     * 通过AtomicBoolean实现线程中断
     */
    public static void m2_atomicBoolean() {
        new Thread(() ->{
            while (true){
                if (atomicBoolean.get()){
                    System.out.println(Thread.currentThread().getName() + "\t atomicBoolean被修改为: " + atomicBoolean + ", 程序停止");
                    break;
                }
                System.out.println("通过 atomicBoolean 来实现中断线程");
            }
        },"t1").start();

        try {
            TimeUnit.MILLISECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            atomicBoolean.set(true);
        },"t2").start();
    }


    /**
     * 通过volatile实现线程中断，因为被volatile修饰的变量，线程之间可见
     */
    public static void m1_volatile() {
        new Thread(() ->{
            while (true){
                if (isStop){
                    System.out.println(Thread.currentThread().getName() + "\t isStop被修改为: " + isStop + ", 程序停止");
                    break;
                }
                System.out.println("通过 volatile 来实现中断线程");
            }
        },"t1").start();

        try {
            TimeUnit.MILLISECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            isStop = true;
        },"t2").start();
    }

}
